﻿using Autofac;
using Autofac.Integration.Mvc;
using MediatR;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Reflection;
using System.Web.Compilation;
using System.Web.Mvc;
using Zj.OpenAuth.Repository.Models;

namespace Zj.OpenAuth.Mvc
{
    /// <summary>
    /// ioc utility autofac extension
    /// </summary>
    public static class AutofacExt
    {
        private static IContainer _container;



        /// <summary>
        /// autofac init, register type 
        /// </summary>
        public static void InitAutofac()
        {
            var builder = new ContainerBuilder();

            var assemblies = BuildManager.GetReferencedAssemblies().Cast<Assembly>().ToList();//get all assemblies in current application

            builder.RegisterType(typeof(OpenAuthDbContext)).As(typeof(DbContext));

            builder.RegisterAssemblyTypes(assemblies.ToArray())//get asembly ends with some keywords 
                .Where(t => t.Name.EndsWith("UnitWork")
                        || t.Name.EndsWith("Repository")
                        || t.Name.EndsWith("CmdHandler")
                        || t.Name.EndsWith("AppService"))
                .AsImplementedInterfaces();//as interface


            #region obsolete
            //register repository base operation and unit work
            //builder.RegisterType(typeof(OpenAuthDbContext)).As(typeof(DbContext));
            //builder.RegisterGeneric(typeof(BaseRepository<>)).As(typeof(IRepository<>));
            //builder.RegisterType(typeof(UnitWork)).As(typeof(IUnitWork));

            ////register application layer
            //builder.RegisterAssemblyTypes(Assembly.GetAssembly(typeof(IDepartmentAppService)))
            //    .AsImplementedInterfaces();

            ////register domain service
            ////builder.RegisterAssemblyTypes(Assembly.GetAssembly(typeof(AuthoriseService)))
            ////    .Where(u => u.Namespace == "OpenAuth.Domain.Service"
            ////    || u.Namespace == "OpenAuth.Domain.Interface");


            ////register repository
            //builder.RegisterAssemblyTypes(Assembly.GetAssembly(typeof(DepartmentRepository)))
            //    .AsImplementedInterfaces(); 
            #endregion

            #region MediatR.
            builder.RegisterType<Mediator>()
                       .As<IMediator>()
                       .InstancePerLifetimeScope();

            // request handlers
            builder
              .Register<SingleInstanceFactory>(ctx =>
              {
                  var c = ctx.Resolve<IComponentContext>();
                  return t => c.TryResolve(t, out var o) ? o : null;
              })
              .InstancePerLifetimeScope();

            // notification handlers
            builder
              .Register<MultiInstanceFactory>(ctx =>
              {
                  var c = ctx.Resolve<IComponentContext>();
                  return t => (IEnumerable<object>)c.Resolve(typeof(IEnumerable<>).MakeGenericType(t));
              })
              .InstancePerLifetimeScope(); 
            #endregion

            // register controller
            builder.RegisterControllers(Assembly.GetExecutingAssembly());

            builder.RegisterModelBinders(Assembly.GetExecutingAssembly());
            builder.RegisterModelBinderProvider();

            // OPTIONAL: Register web abstractions like HttpContextBase.

            //builder.RegisterModule<AutofacWebTypesModule>();

            // OPTIONAL: Enable property injection in view pages.
            builder.RegisterSource(new ViewRegistrationSource());

            // register all attributes
            builder.RegisterFilterProvider();

            // Set the dependency resolver to be Autofac.
            _container = builder.Build();
            DependencyResolver.SetResolver(new AutofacDependencyResolver(_container));
        }



        /// <summary>
        /// get object from container
        /// </summary>
        /// <typeparam name="T"></typeparam>

        public static T GetFromFac<T>()
        {
            return _container.Resolve<T>();
            //   return (T)DependencyResolver.Current.GetService(typeof(T));

        }
    }
}